# -*- coding: utf-8 -*-

'''
Created on 2010/07/15

@author: saburo
'''

from pyrfid.DataProtocol.Driver.DriverInterface import DriverInterface
from abc import abstractmethod
from pyrfid.DataProtocol.Exception.ExecutionCodeException.InterrogatorCommunicationErrorException import InterrogatorCommunicationErrorException
from pyrfid.DataProtocol.Driver.SessionManager import SessionManager

import sys
from pyrfid.DataProtocol.Exception.ExecutionCodeException.ExecutionCodeException import ExecutionCodeException
from pyrfid.DataProtocol.Exception.ExecutionCodeException.InvalidParameterException import InvalidParameterException
from pyrfid.DataProtocol.Driver.DriverException.SessionInValidException import SessionInValidException
from pyrfid.Util.Util import Util

class UHFDriver(DriverInterface):
    
    __CURRENT_LEVEL = 0
    LEVEL_0 = 0 #controle handler
    LEVEL_1 = 1 #uncontrole handler
    __IS_BLOCK = False
    __session_manager = ""
    
    #Address Information ###########################
    UII = 1
    TID = 2
    USER = 3    
    AFI_INFO = {"ADDRESS_ON_BYTE":2, "BANK":UII}
    DSFID_INFO = {"ADDRESS_ON_BYTE":0, "BANK":USER}
    ################################################
    
    def __init__(self, is_block, level, life_time):
        self.__CURRENT_LEVEL = level
        self.__IS_BLOCK = is_block
        
        if level == self.LEVEL_0:
            self.__session_manager = SessionManager(life_time)
        
    @abstractmethod
    def _turnOfF(self):
        pass
    
    @abstractmethod
    def _turnOn(self):
        pass
    
    @abstractmethod
    def _writeCommand(self, tag_id, memory_type, start_address, write_data):
        pass
    
    @abstractmethod
    def _readCommand(self, tag_id, memory_type, start_address, width):
        pass
    
    @abstractmethod
    def _inventoryCommand(self): 
        pass    
    
    @abstractmethod
    def _selectCommand(self):
        pass    

    def __cacheReadCommand(self, tag_id, memory_type, start_address, width):
        cache_data = ""
        if self.__CURRENT_LEVEL == self.LEVEL_0:
            virtual_tag = self.__session_manager.getVirtualTag(tag_id)
            if UHFDriver.USER == memory_type:
                cache_data = virtual_tag.getUserMemory(start_address, width)
        return cache_data
        
    def __convertByteToWord(self):
        pass
    
    def getSessionManager(self):
        return self.__session_manager
    
    def __sessionManager(self, tag_id):
        if self.__CURRENT_LEVEL == self.LEVEL_0:
            print "Session Manager boot"
            pass
        else:
            pass
        
    def _createSession(self, tag_id):
        print "create session"
        self._turnOff()
        self._turnOn()                
#            select Command
#            result =  self._selectCommand(0, 0, tag_id, 0 , UHFDriver.TID)        
#            inventory Command
        handle_value, create_time, AFI, UII = self._inventoryCommand()
        self.__session_manager.setSession(tag_id, handle_value, create_time)
        
        return True
    
    def writeUserMemory(self, tag_id, start_address, write_data, is_back_write=False):
        """
        tag_id: tag Id
        start_address: the start_address does not include dsfid
        """
        write_start_address = len(self.getDSFID(tag_id)) / 2 + start_address
        print "write address is ",write_start_address
        print "write data is ", write_data         
        self.writeData(tag_id, write_start_address, write_data, UHFDriver.USER, is_back_write)        
    
    def writeData(self, tag_id, start_address, write_data, write_memory_bank=3, is_back_write=False):
        
        print "WRITE DATA ---------------", start_address, len(write_data)
        ################################################
        #Create writeData sequence
        if start_address % 2 != 0:
            readAddress = start_address / 2
            result = self.readData(tag_id, readAddress * 2, 1, write_memory_bank)            
            write_data = result + write_data
        
        #read
        if len(write_data) % 4 != 0:
            readAddress = start_address + len(write_data) / 2
            result = self.readData(tag_id, readAddress, 1, write_memory_bank)
            write_data = write_data + result
        ################################################
                
        startOnWordAddress = start_address / 2        
        
        if self.isBlockWrite == True:
            self._blockWriteCommand(tag_id, write_memory_bank, startOnWordAddress, write_data)
            return True        
        
        print "------------------------------------------------------------------------------------1"
        print write_data
        
        #not original Code        
        writing_address = startOnWordAddress
        if is_back_write == True:        
            writing_address = startOnWordAddress + len(write_data) / 4 - 1
        
        writeDataByWrodArray = list()
        for writeDataIndex  in range(len(write_data) / 4):
            writeDataByWrodArray.append(write_data[writeDataIndex * 4:(writeDataIndex * 4) + 4])
        
        #Write data ############################################################################################
        if is_back_write == True:
            writeDataByWrodArray.reverse()
        
        print writeDataByWrodArray
        print "------------------------------------------------------------------------------------"
        # endAddress = startOnWordAddress
        for writeIndex in range(len(writeDataByWrodArray)):            
            commandExecuted = False    
            while commandExecuted == False:                
                try:
                    read_data = ""
                    if self.__CURRENT_LEVEL == UHFDriver.LEVEL_0:                        
                        read_data = self.getSessionManager().getVirtualTag(tag_id, DriverInterface.UHF_VIRTUAL_TAG_TYPE).getUserMemory(writing_address, len(writeDataByWrodArray[writeIndex]) / 4)
                    
                    if read_data != writeDataByWrodArray[writeIndex]:
                        print "write address is ", writing_address                        
                        self._writeCommand(tag_id, write_memory_bank, writing_address, writeDataByWrodArray[writeIndex])                    

                        #Update DataManager
                        if write_memory_bank == UHFDriver.USER:
                            self.__session_manager.getVirtualTag(tag_id, DriverInterface.UHF_VIRTUAL_TAG_TYPE).updateUserMemory(writing_address, writeDataByWrodArray[writeIndex])
                        elif write_memory_bank == UHFDriver.UII:
                            self.__session_manager.getVirtualTag(tag_id, DriverInterface.UHF_VIRTUAL_TAG_TYPE).updateUII(writing_address, writeDataByWrodArray[writeIndex])                    
                    else:
                        print "non write data ", read_data, " : " , writeDataByWrodArray[writeIndex]
                    commandExecuted = True
                    
                except (InterrogatorCommunicationErrorException, SessionInValidException) as error:
                    if self.__CURRENT_LEVEL == self.LEVEL_0:                    
                        self._createSession(tag_id)
                    
                    #check USER, UII
                    #User-Memory
                    all_user_memory = self.__session_manager.getVirtualTag(tag_id, DriverInterface.UHF_VIRTUAL_TAG_TYPE).getAllUserMemory()
                    current_all_memory = self.readUserMemory(tag_id, 0, self.getUserMemoryLength(tag_id, self.UII))
                    #compare all_user_memory with current_all_memory
                    print "EXCEPTION ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                    print "EXCEPTION ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                    print "EXCEPTION ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                    
                except ExecutionCodeException as error:
                    print error
                    raise error
            print is_back_write
            print is_back_write
            print is_back_write
            if is_back_write == True:
                writing_address = writing_address - 1
            else:
                writing_address = writing_address + 1
            
        #END Write data ############################################################################################         
        return True
    
    
    def readUserMemory(self, tag_id, start_address, width):
        """
        tag_id: tag Id
        start_address: the start_address does not include dsfid
        """
        read_start_address = len(self.getDSFID(tag_id)) / 2 + start_address
        read_data = self.readData(tag_id, read_start_address, width, UHFDriver.USER)
        return read_data
    
    def readData(self, tag_id, start_address, width, read_bank_type=3):        
        print "READ Data---------------"
        
        original_start_address = start_address
        startReadPositionOnWord = start_address / 2
        
        #convert byte to word        
        lengthOfReadOnWord = width / 2
        
        #for width 1
        if lengthOfReadOnWord == 0:
            lengthOfReadOnWord = 1
        
        if (start_address + width) % 2 != 0:
            lengthOfReadOnWord += 1
        
        if start_address % 2 == 1:
            start_address -= 1
            lengthOfReadOnWord += 1
        
        #access Command
        isExecuted = False
        while isExecuted == False:
            try:  
                response = self._readCommand(tag_id, read_bank_type, startReadPositionOnWord, lengthOfReadOnWord)
                isExecuted = True
            except (InterrogatorCommunicationErrorException, SessionInValidException) as error:
                #session
                print "occur InterrogatorCommunicationErrorException"                
                self._createSession(tag_id)
                continue
        
        if read_bank_type == UHFDriver.UII:
            self.__session_manager.getVirtualTag(tag_id, DriverInterface.UHF_VIRTUAL_TAG_TYPE).updateUII(startReadPositionOnWord, response)
        elif read_bank_type == UHFDriver.USER:
            self.__session_manager.getVirtualTag(tag_id, DriverInterface.UHF_VIRTUAL_TAG_TYPE).updateUserMemory(startReadPositionOnWord, response)
#        if startReadPositionOnWord == 0 and width == SessionManager.getInstance(tag_id).getDataManager().userMemoryLength:
#            SessionManager.getInstance(tag_id).getDataManager().setAllData(response)
        
        if original_start_address % 2 == 1:
            response = response[2:]        
        
        response = response[:width * 2] 
        return response
        
    def configureAFI(self, tag_id, afi):
        print "configure AFI"
        # Length (5bit) + User-Memory Indicator(1bit) + XPC Indicator(1bit) + ISO or EPC (1bit) + AFI(8bit)
        
        write_data = Util.convertBitToHex('00110' + '1' + '0' + '1') + afi.getAFIonHex()
        self.writeData(tag_id, UHFDriver.AFI_INFO["ADDRESS_ON_BYTE"], write_data, UHFDriver.AFI_INFO["BANK"])
        return True
    
    def getAFI(self, tag_id):  
        afi = self.readData(tag_id, self.AFI_INFO["ADDRESS_ON_BYTE"], 1, self.AFI_INFO["BANK"])
        return afi
    
    def configureDSFID(self, tag_id, dsfid):
        print "START configure DSFID==============================================================="        
        self.writeData(tag_id, self.DSFID_INFO["ADDRESS_ON_BYTE"], dsfid)                
        print "END configure DSFID==============================================================="                
        return True    
    
    def getDSFID(self, tag_id):        
        print "START getDSIFD==============================================================="        
        dsfid = self.readData(tag_id, self.DSFID_INFO["ADDRESS_ON_BYTE"], 1, self.DSFID_INFO["BANK"])
        print "END getDSIFD==============================================================="
        return dsfid
    
    def getUserMemoryLength(self, tagId, executeBankType=3):
        """proposal method"""
        searchAddressIndex = 10
        searchWidth = searchAddressIndex
        tempIndex = 0
        
        while True:
            tempIndex = searchAddressIndex
            try:
                self._readCommand(tagId, executeBankType , searchAddressIndex, 1)
                searchAddressIndex = searchAddressIndex + searchWidth
            except InvalidParameterException:
                searchAddressIndex = searchAddressIndex - searchWidth
                searchWidth = searchWidth / 2
                if searchWidth == 0:
                    searchWidth = 1
                searchAddressIndex = searchAddressIndex + searchWidth
            except InterrogatorCommunicationErrorException:               
                continue
                
            except Exception, error:
                raise "Error", error
            if searchAddressIndex == tempIndex:
                break
        
        length = searchAddressIndex * 2 - (len(self.getDSFID(tagId)) / 2) 
        return length
